import { Injectable } from '@nestjs/common';
import { DbService } from '../../db/db.service';
import PageDto from './dto/page.dto';
import { FindOptionsWhere, In, Like } from 'typeorm';
import { DeviceParams } from '@app/db/entity/DeviceParams';
import CreateDto from './dto/create.dto';
import * as dayjs from 'dayjs';
import UpdateDto from './dto/update.dto';
import { DeviceType } from '@app/db/entity/DeviceType';

@Injectable()
export class DeviceParamsService {
    constructor(
        private readonly db:DbService
    ){}

    
    async options(merchantId:number) {
        return this.db.deviceParams.find({merchantId}, {id : true, name : true, params : () => true})
    }

    async page(dto:PageDto, merchantId:number) {
        let result:PaginationResult<DeviceParams & {deviceType? : DeviceType, paramsExplain? : {[key:string] : any}}> = {
            total : 0,
            rows : []
        }

        let where:FindOptionsWhere<DeviceParams> = {
            merchantId
        }

        if(dto.name) {
            where.name = Like('%' + dto.name + '%')
        }

        result.total = await this.db.deviceParams.count(where)

        

        if(result.total > 0) {
            result.rows = await this.db.deviceParams.pagination(dto.pageNo, dto.pageSize, where, null, {id : 'DESC'})
            const typeIds:number[] = []
            const paramKeys:string[] = []
            result.rows.forEach(row => {
                if(!typeIds.includes(row.deviceTypeId)) {
                    typeIds.push(row.deviceTypeId)
                }

                if(row.params) {
                    for(let k in row.params) {
                        if(!paramKeys.includes(k)) {
                            paramKeys.push(k)
                        }
                    }
                }
            })
    
            const deviceTypes = await this.db.deviceType.find({id : In(typeIds)}, {id : true, name : true})
            const paramsFields = await this.db.deviceParamsField.find({key : In(paramKeys)}, {id : true, key : true, name : true})

            result.rows.forEach(row => {
                const deviceType = deviceTypes.find(item => item.id == row.deviceTypeId)
                row.deviceType = deviceType

                if(row.params) {
                    const paramsExplain:{[key:string] : any} = {}
                    for(let k in row.params) {
                        const field = paramsFields.find(item => item.key == k)
                        paramsExplain[field.name] = row.params[k]
                    }

                    row.paramsExplain = paramsExplain
                }

            })
        }

        return result
    }

    
    async add(dto:CreateDto, memberId:number, merchantId:number) {

        if(true == await this.db.deviceParams.isExistsByWhere({name : dto.name, merchantId})) throw new Error('已存在相同的名称')


        return this.db.deviceParams.insert({...dto, creatorId : memberId, merchantId : merchantId, createTime : dayjs().unix()})
    }

    async update(dto:UpdateDto, merchantId:number) {
        let fields = Object.keys(dto) as (keyof DeviceParams)[]
        if(fields.length == 0) return true

        const row = await this.db.deviceParams.findOne({ id : dto.id })
        
        if(!row || row.merchantId != merchantId) return false

        let updateData:KeyToValueType<DeviceParams> = {}

        for(let k in row) {
            if(k in dto) {
                if(k == 'params') {
                    if(JSON.stringify(dto.params) == JSON.stringify(row.params)) continue
                    
                }else {
                    if(row[k] == dto[k]) continue
                }
    
                updateData[k] = dto[k]
            }
            
        }

        if(Object.keys(updateData).length == 0) return true

        if(updateData.name && (true == await this.db.deviceParams.isExistsByWhere({name : dto.name, merchantId}))) throw new Error('已存在相同的名称')
       
        
        updateData.updateTime = dayjs().unix()

        return this.db.deviceParams.update({id : dto.id}, updateData)
    }

    async del(id:number, merchantId:number) {
        let row = await this.db.deviceParams.findOne({ id }, ['id', 'merchantId'])
        if(!row || row.merchantId != merchantId) return
        return this.db.deviceParams.delete({id : id})
    }
}
